import { execSync } from "node:child_process";
import path from "node:path";
import chalk from "chalk";
import fs from "fs-extra";
import type { ProjectOptions } from "./types";
import { AI_PROVIDER_CONFIG } from "./types";
import { createSpinner } from "./utils/animation";
import { installProviderDependency } from "./utils/dependency-installer";
import fileManager from "./utils/file-manager";
import { configureMcpForIde, showMcpConfigurationMessage } from "./utils/mcp-config";
import { getAllTemplates } from "./utils/templates";

export const createProject = async (options: ProjectOptions, targetDir: string): Promise<void> => {
  // Directory should already exist with base dependencies installed
  // Just check if we need to handle any edge cases
  const files = fs.readdirSync(targetDir);
  if (files.length === 0) {
    throw new Error(
      `The directory ${options.projectName} is empty. Something went wrong with base installation.`,
    );
  }

  // Animated spinner
  const spinner = createSpinner("Creating project files...");
  spinner.start();

  try {
    // Directory structure already created during base dependency installation

    // Try processing templates, use default content if error occurs
    spinner.text = "Processing templates...";
    const templates = getAllTemplates();

    let templateCounter = 0;
    const totalTemplates = templates.length;

    for (const template of templates) {
      templateCounter++;
      spinner.text = `Processing template ${templateCounter}/${totalTemplates}: ${chalk.dim(template.targetPath)}`;

      await fileManager.processTemplateFile(template, options, targetDir);
    }

    // Create .gitignore file
    spinner.text = "Setting up git configuration...";
    await fileManager.writeFile(
      path.join(targetDir, ".gitignore"),
      `# Dependencies
node_modules
.pnp
.pnp.js

# Build outputs
dist
build
.turbo

# Environment
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# Cache
.eslintcache
.DS_Store
*.tsbuildinfo
.cache

# Editor directories and files
.idea
.vscode/*
!.vscode/extensions.json
!.vscode/settings.json
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

# Test coverage
coverage
.nyc_output

# Yarn 2 non zero-install
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.pnp.*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# parcel-bundler cache (https://parceljs.org/)
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/

# VoltAgent
.voltagent

# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp
.cache

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*


# NX
.nx


.voltagent

# Create VoltAgent App
!packages/create-voltagent-app/templates/base/.env

# cursor
.cursor
`,
    );

    // Configure MCP for selected IDE
    if (options.ide && options.ide !== "none") {
      spinner.text = `Configuring MCP Docs Server for ${options.ide}...`;
      await configureMcpForIde(targetDir, options);
      showMcpConfigurationMessage(options.ide);
    }

    spinner.succeed(chalk.green("VoltAgent project created successfully! 📁"));

    // Install provider-specific dependency
    if (options.aiProvider) {
      const providerConfig = AI_PROVIDER_CONFIG[options.aiProvider];
      await installProviderDependency(
        targetDir,
        providerConfig.package,
        providerConfig.packageVersion,
        providerConfig.extraPackages || [],
      );
    }

    // Initialize git repository
    const gitSpinner = createSpinner("Initializing git repository...");
    gitSpinner.start();

    try {
      execSync("git init", {
        cwd: targetDir,
        stdio: "ignore",
      });

      // Add initial commit
      execSync("git add .", {
        cwd: targetDir,
        stdio: "ignore",
      });

      execSync('git commit -m "Initial commit from create-voltagent-app"', {
        cwd: targetDir,
        stdio: "ignore",
      });

      gitSpinner.succeed(chalk.green("Git repository initialized! 🎯"));
    } catch (_error) {
      gitSpinner.warn(chalk.yellow("Git init skipped (git not installed or failed)"));
    }
  } catch (error) {
    spinner.fail(
      chalk.red(
        `Failed to create project: ${error instanceof Error ? error.message : String(error)}`,
      ),
    );
    throw error;
  }
};
